package com.seanzx.dp.processor;

import com.seanzx.dp.common.Persist;
import com.seanzx.dp.condition.ConditionTree;
import com.seanzx.dp.entity.Table;
import com.seanzx.dp.memory.TableBuffer;
import com.seanzx.dp.common.DBFileInputStream;
import com.seanzx.dp.common.DBFileOutputStream;
import com.seanzx.common.Result;
import com.seanzx.common.ResultCode;
import com.seanzx.dp.entity.Column;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class DataProcessor {

    public Result<Integer> insert(String databaseName, String tableName, List<Column> columns, List<String> values) throws IOException {
        File file = Persist.getTable(databaseName, tableName);
        if (!file.exists()) {
            return Result.of(ResultCode.TABLE_NOT_EXISTS, 0);
        }
        try (
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file, true));
                DBFileOutputStream outputStream = new DBFileOutputStream(bufferedOutputStream)
        ) {
            for (int i = 0; i < columns.size(); i++) {
                outputStream.write(columns.get(i), values.get(i));
            }
        }
        return Result.ok(1);
    }

    public Result<Integer> delete(String databaseName, String tableName, ConditionTree conditions) throws IOException {
        File file = Persist.getTable(databaseName, tableName);
        if (!file.exists()) {
            return Result.of(ResultCode.TABLE_NOT_EXISTS, 0);
        }
        List<List<String>> existsRows = new ArrayList<>();
        Optional<Table> optional = TableBuffer.getTable(databaseName, tableName);
        if (!optional.isPresent()) {
            return Result.of(ResultCode.TABLE_NOT_EXISTS, 0);
        }
        List<Column> columns = optional.get().getColumns();
        try (
                BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
                DBFileInputStream inputStream = new DBFileInputStream(bufferedInputStream)
        ) {
            List<String> row;
            while ((row = inputStream.readRow(columns)) != null) {
                if (!conditions.test(row)) {
                    existsRows.add(row);
                }
            }
        }
        try (
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
                DBFileOutputStream outputStream = new DBFileOutputStream(bufferedOutputStream)
        ) {
            for (List<String> existsRow : existsRows) {
                for (int i = 0; i < existsRow.size(); i++) {
                    outputStream.write(columns.get(i), existsRow.get(i));
                }
            }
        }
        return Result.ok(1);
    }

    public Result<List<List<String>>> select(String databaseName, String tableName, List<Column> columns, ConditionTree conditions) throws IOException {
        File file = Persist.getTable(databaseName, tableName);
        if (!file.exists()) {
            return Result.of(ResultCode.TABLE_NOT_EXISTS, null);
        }
        List<List<String>> resultList = new ArrayList<>();
        try (
                BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
                DBFileInputStream inputStream = new DBFileInputStream(bufferedInputStream)
        ) {
            List<String> row;
            while ((row = inputStream.readRow(columns)) != null) {
                if (conditions == null || conditions.test(row)) {
                    resultList.add(row);
                }
            }
        }
        return Result.ok(resultList);
    }

    public Result<List<List<String>>> select(String databaseName, String tableName, List<Column> columns,
                                             List<String> filterColumns, ConditionTree conditions) throws IOException {
        File file = Persist.getTable(databaseName, tableName);
        if (!file.exists()) {
            return Result.of(ResultCode.TABLE_NOT_EXISTS, null);
        }
        List<List<String>> resultList = new ArrayList<>();
        try (
                BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
                DBFileInputStream inputStream = new DBFileInputStream(bufferedInputStream)
        ) {
            List<String> row;
            while ((row = inputStream.readRow(columns, filterColumns)) != null) {
                if (conditions == null || conditions.test(row)) {
                    resultList.add(row);
                }
            }
        }
        return Result.ok(resultList);
    }
}
